package com.molihub.component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.molihub.entity.RequestMessage;
import com.molihub.entity.User;
import com.molihub.service.RequestMessageService;
import com.molihub.service.UserService;
import com.molihub.utils.LogUtils;
import com.molihub.utils.SpringUtils;
import com.molihub.utils.UrlUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: MyWebSocketHandler
 * @Description: 处理WebSocket的几种情况
 * @author: GGBOY
 * @date 2020/1/30 22:49
 * @Version: 1.0
 **/
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    /**
     * 储存每个用户所对应的channelID
     */
    private static Map<Integer, Channel> restoreChannel = new HashMap<>();
    private static Logger logger = LogUtils.getInstance(MyWebSocketHandler.class);

    private UserService userService = SpringUtils.getBean(UserService.class);
    private RequestMessageService requestMessageService = SpringUtils.getBean(RequestMessageService.class);

    /**
     * 与客户端建立链接时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("与客户端建立连接，通道开启！");
        //添加到channelGroup通道组
        MyChannelHandlerPool.channelGroup.add(ctx.channel());
    }

    /**
     * 与客户端断开连接时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        logger.info("与客户端断开连接，通道关闭！");
        //添加到channelGroup 通道组
        MyChannelHandlerPool.channelGroup.remove(ctx.channel());
    }

    /**
     * 客户端发送消息处理
     *
     * @param ctx
     * @param msg 接收的客户端发送过来的消息
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //首次连接是FullHttpRequest
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            String uri = request.uri();
            logger.info("传递过来的URL为：" + uri);
            uri = UrlUtils.getURLDecoderString(uri);
            logger.info("传递过来的URL经过编码为：" + uri);
            Map paramMap = getUrlParams(uri);
            // 根据用户名获得对应的用户id
            Integer userId = userService.getUserByUserName((String) paramMap.get("name")).getUserId();
            // 存储这个用户对应的channel
            restoreChannel.put(userId, ctx.channel());

            logger.info("接收到的参数是：" + JSON.toJSONString(paramMap) + " 获取到的用户id为：" + userId);
            //如果url包含参数，需要处理
            if (uri.contains("?")) {
                String newUri = uri.substring(0, uri.indexOf("?"));
                logger.info(newUri);
                request.setUri(newUri);
            }

        } else if (msg instanceof TextWebSocketFrame) {
            //正常的TEXT消息类型
            TextWebSocketFrame frame = (TextWebSocketFrame) msg;
        }
        super.channelRead(ctx, msg);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext,
                                TextWebSocketFrame textWebSocketFrame) throws Exception {
        logger.info("channelRead0..");
        logger.info("客户端收到服务器数据：" + textWebSocketFrame.text());
        JSONObject jsonObject = JSONObject.parseObject(textWebSocketFrame.text());
        // 分割消息，获取申请人:A和被添加人:B
        String A = jsonObject.getString("A");
        String B = jsonObject.getString("B");
        // 获得消息类型
        String flag = (String) jsonObject.get("flag");
        // 接收到申请加的好友用户名，进行添加，发送好友请求
        // 申请人
        User userApplicant = userService.getUserByUserName(A);
        // 被添加人
        User userHandler = userService.getUserByUserName(B);

        logger.info(userApplicant.toString());
        // 将双方用户的详细信息也添加到消息内容中去
        jsonObject.put("aUserInfo", userApplicant);
        jsonObject.put("bUserInfo", userHandler);

        // 获取被添加人所对应的channel,进行通知
        Channel channel = restoreChannel.get(userHandler.getUserId());

        // 创建一个请求消息实体，封装对应的数据
        RequestMessage requestMessage = new RequestMessage();
        requestMessage.setAUserId(userApplicant.getUserId());
        requestMessage.setBUserId(userHandler.getUserId());
        requestMessage.setMessageContent(jsonObject.toJSONString());
        requestMessage.setFlag(Integer.parseInt(flag));
        // 将请求消息记录在数据库中
        requestMessageService.addMessage(requestMessage);
        if (channel != null) {
            // 用户在线
            // 将申请人的信息发送给被添加用户
            channel.writeAndFlush(new TextWebSocketFrame(jsonObject.toJSONString()));
        }


    }

    /**
     * 给全体在线的用户发送信息
     *
     * @param message 需要发送的信息
     */
    private void sendAllMessage(String message) {
        //收到信息后，群发给所有channel
        MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(message));
    }

    /**
     * A用户向B用户发送消息
     *
     * @param aId     a用户的ID
     * @param bId     b用户的ID
     * @param message 要发送的信息
     * @return void
     * @author GGBOY
     * @date 2020/1/31
     */
    public static void aSendMessageToB(Integer aId, Integer bId, String message) {
        logger.info("aId: " + aId + " bId: " + bId + " " + message);
        Channel channel = restoreChannel.get(bId);
        // 判断B的Channel是否为空，如果为空，则表示不在线，如果不为空，则表示在线,发送消息
        if (channel != null) {
            // 获取B的channel，向B发送信息
            channel.writeAndFlush(new TextWebSocketFrame(message));
        }

    }


    /**
     * 处理URL中的参数
     *
     * @param url 客户端传递过的URL参数
     * @return java.util.Map
     * @author GGBOY
     * @date 2020/1/31
     */
    private static Map getUrlParams(String url) {
        Map<String, String> map = new HashMap<>();
        url = url.replace("?", ";");
        if (!url.contains(";")) {
            return map;
        }
        if (url.split(";").length > 0) {
            String[] arr = url.split(";")[1].split("&");
            for (String s : arr) {
                String key = s.split("=")[0];
                String value = s.split("=")[1];
                map.put(key, value);
            }
            return map;

        } else {
            return map;
        }
    }


}
